package com.gooluke.mall.order.service.impl;

import com.gooluke.mall.api.po.goods.TGoodsInfo;
import com.gooluke.mall.api.po.order.TOrderInfo;
import com.gooluke.mall.api.po.user.TUserInfo;
import com.gooluke.mall.api.service.goods.GoodsService;
import com.gooluke.mall.api.service.order.DubboOrderService;
import com.gooluke.mall.api.service.user.UserService;
import com.gooluke.mall.order.integration.mapper.OrderInfoMapper;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author : chennengyuan
 */
@Slf4j
@Service
public class OrderServiceImpl implements DubboOrderService {

    private static final Logger LOGGER = LoggerFactory.getLogger(OrderServiceImpl.class);

    private static final String ORDER_INFO_KEY_PREFI = "orderInfo_";
    private static final String LOCK_KEY = "SELECT_DATABASE_ORDER_INFO_LOCK";

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @DubboReference
    private GoodsService goodsService;

    /**
     * random（默认）：随机选择一个提供者。
     * roundrobin：轮询选择，按公约后的权重设置轮询比率。
     * leastactive：最少活跃调用数，相同活跃数的随机，活跃数指调用前后计数差。
     * consistenthash：一致性Hash，相同参数的请求总是发到同一个提供者。
     */
    @DubboReference(loadbalance = "roundrobin")
    private UserService userService;

    @Override
    public TOrderInfo selectOrderInfo(String orderId) {
        String key = ORDER_INFO_KEY_PREFI + orderId;
        TOrderInfo orderInfo = (TOrderInfo) redissonClient.getBucket(key).get();
        if (orderInfo != null) {
            log.info("从缓存中获取订单信息：{}", orderInfo);
            return orderInfo;
        }
        //模拟查询数据库
        RLock lock = redissonClient.getLock(LOCK_KEY);
        try {
            lock.lock();
            orderInfo = TOrderInfo.builder().orderNo(orderId).build();
            redissonClient.getBucket(key).set(orderInfo);
            log.info("从数据库中获取订单信息：{}", orderInfo);
        } catch (Exception e) {
            log.error("获取数据库订单信息失败：{}", e.getMessage());
        } finally {
            lock.unlock();
        }
        return orderInfo;
    }

    @Override
    public int insert(TOrderInfo orderInfo) {
        return orderInfoMapper.insert(orderInfo);
    }

    @Override
    @GlobalTransactional
    public void business() {
        LOGGER.info("purchase begin ... xid: " + RootContext.getXID());
        TOrderInfo orderInfo = TOrderInfo.builder()
                .orderNo("order_no_" + RandomStringUtils.random(10, "1234567890"))
                .userId("system").build();
        TGoodsInfo goodsInfo = TGoodsInfo.builder()
                .goodsNo("goods_" + RandomStringUtils.random(10, "1234567890"))
                .goodsName("name_" + RandomStringUtils.random(10, "1234567890")).build();
        TUserInfo userInfo = TUserInfo.builder()
                .userId("user_" + RandomStringUtils.random(10, "1234567890"))
                .userName("name_" + RandomStringUtils.random(10, "1234567890")).build();
        new TOrderInfo().setOrderNo("O_" + RandomStringUtils.random(10,"1234567890"));
        insert(orderInfo);
        String s = "251235";
        goodsService.insert(goodsInfo);
        String s2 = "58085023";
        userService.insert(userInfo);
        String s3 = "5808235023";
        //这里抛出异常，观察各数据库回滚情况
        int a = 1/0;
    }
}
